package top.ninwoo.weixingsim.service.impl;


import top.ninwoo.weixingsim.entity.WeiXingData;
import top.ninwoo.weixingsim.service.Weixing;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class WeixingImpl implements Weixing {
    private static double G = 6.754*Math.pow(10,-11);
    private static double EARTHMASS = 5.965*Math.pow(10,24);
    private static double GM = G*EARTHMASS;

    @Override
    public List<Map> parseTxt(File file) {
        String str;
        List<Map> maps = new ArrayList<Map>();
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            while((str = br.readLine()) != null){
                if(str.equals("-------------")){
                    //WeiXing initwx = new WeiXing();
                    Map<String,String> map = new HashMap();
                    str = br.readLine();
                    while(str.equals("-------------")==false){
                        String[] split = str.split("=");
                        //if(split(0)==initwx.)
                        map.put(split[0], split[1]);
                        str = br.readLine();
                    }
                    maps.add(map);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return maps;
    }

    @Override
    public  WeiXingData initWX(Class wx, Map map) throws IllegalAccessException {
        WeiXingData initwx = new WeiXingData();
        Field[] fields = wx.getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);
            if (field.getType() == Float.class) {
                field.set(initwx, Float.parseFloat((String) map.get(field.getName())));
            } else if (field.getType() == String.class) {
                field.set(initwx, map.get(field.getName()));
            }else if (field.getType() == Boolean.class) {
                if(map.get(field.getName()).equals("true")){
                    field.set(initwx, true);
                }else{field.set(initwx, false);}
            }
        }
        return initwx;
    }

    @Override
    public List<WeiXingData> initNet(List<Map> maps) throws IllegalAccessException {
        List<WeiXingData> initnet = new ArrayList<>();

        for(int i=0;i<maps.size();i++){
            WeiXingData wx = new WeiXingData();
            wx = this.initWX(WeiXingData.class,maps.get(i));
            initnet.add(wx);
        }
        return initnet;
    }

    @Override
    public List<WeiXingData> addSpeed(List<WeiXingData> wx) {
        for(int i=0;i<wx.size();i++){
            if(wx.get(i).getTag().equals(true)){
                wx.get(i).setSpeed(Math.sqrt(GM/Math.pow(wx.get(i).getHigh(),2)));}
            else{wx.get(i).setSpeed((-1)*Math.sqrt(GM/Math.pow(wx.get(i).getHigh(),2)));}
        }
        return wx;
    }

    @Override
    public List<WeiXingData> addAxis(List<WeiXingData> wx) {
        for (int i = 0; i < wx.size(); i++) {
            Float High = wx.get(i).getHigh();
            Double hudu = Math.toRadians(wx.get(i).getSpeed() * wx.get(i).getLastime());
            Double Alpha = Math.toRadians(wx.get(i).getAlpha());
            Double Beta = Math.toRadians(wx.get(i).getBeta());
            Double Gamma = Math.toRadians(wx.get(i).getGamma());
            wx.get(i).setXaxis(High * Math.cos(hudu + Gamma) * Math.sin(Beta) + High * Math.sin(hudu + Gamma) * Math.cos(Alpha) * Math.cos(Beta));
            wx.get(i).setYaxis(High * Math.cos(hudu + Gamma) * Math.cos(Beta) - High * Math.sin(hudu + Gamma) * Math.cos(Alpha) * Math.sin(Beta));
            wx.get(i).setZaxis(High * Math.sin(hudu + Gamma) * Math.sin(Alpha));
        }
        return wx;
    }

    @Override
    public boolean addIndex(List<WeiXingData> wx) {
        for(int i=0;i<wx.size();i++){
            wx.get(i).setIndex(i+1);
        }
        return true;
    }

    @Override
    public boolean checkIndex(List<WeiXingData> wx) {
        boolean k=false;
        int tag = 0;
        for(int m=0;m<wx.size();m++){
            if(wx.get(m).getIndex() == m+1){
                tag++;
            }else{
                wx.get(m).setIndex(m+1);
                m=m-1;
            }
        }

        if(tag == wx.size()){
            k = true;
        }
        return k;
    }

    @Override
    public void checkWX(List<WeiXingData> wx) {
        for(int i=0;i<wx.size();i++){
            for(int j=i+1;j<wx.size();j++){
                if(wx.get(i).getName().equals(wx.get(j).getName())){
                    String str = wx.get(i).getName() + i + j;
                    wx.get(j).setName(str);
                }
            }
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    @Override
    public Integer findindex(List<WeiXingData> weiXingDataList, String appName) {
        Integer index = 0;
        for(int i=0;i<weiXingDataList.size();i++){
            if(weiXingDataList.get(i).getName().equals(appName)){
                index = weiXingDataList.get(i).getIndex();
                break;
            }
        }
        return index;
    }

    @Override
    public WeiXingData findWX(List<WeiXingData> weiXingDataList, String appName) {
        WeiXingData wxData = null;
        int k = findindex(weiXingDataList,appName);
        if(k != 0){
            wxData = weiXingDataList.get(k-1);
        }
        return wxData;
    }

    //增加和删除卫星需要反求（球坐标）
    @Override
    public List<WeiXingData> addWX(List<WeiXingData> weiXingDataList, WeiXingData newWX) {
        //先判断是否已存在相同名字的卫星
        WeiXingData wxdata = findWX(weiXingDataList,newWX.getName());
        if(wxdata != null){
            //加上时间这一唯一标识
            newWX.setName(newWX.getName()+System.currentTimeMillis());
        }
        weiXingDataList.add(newWX);

        //修改坐标系
        for(int i=0;i<weiXingDataList.size()-1;i++){
            float gamma = (float) (weiXingDataList.get(i).getGamma()+weiXingDataList.get(i).getLastime()*weiXingDataList.get(i).getSpeed());
            weiXingDataList.get(i).setGamma(gamma);
            weiXingDataList.get(i).setLastime(0);
        }
        this.addIndex(weiXingDataList);
        this.checkIndex(weiXingDataList);
        return weiXingDataList;
    }

    @Override
    public List<WeiXingData> delWX(List<WeiXingData> weiXingDataList, String appName) {
        //找到该卫星
        WeiXingData wxdata = findWX(weiXingDataList,appName);
        if(wxdata != null){
            weiXingDataList.remove(wxdata.getIndex()-1);
        }

        //修改坐标系
        for(int i=0;i<weiXingDataList.size();i++){
            float gamma = (float) (weiXingDataList.get(i).getGamma()+weiXingDataList.get(i).getLastime()*weiXingDataList.get(i).getSpeed());
            weiXingDataList.get(i).setGamma(gamma);
            weiXingDataList.get(i).setLastime(0);
        }

        this.addIndex(weiXingDataList);
        this.checkIndex(weiXingDataList);
        return weiXingDataList;
    }

    //todo 只考虑增加高度一个选项
    @Override
    public List<WeiXingData> changeWX(List<WeiXingData> weiXingDataList, String appName, String field, String val) {
        return null;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    @Override
    public List<WeiXingData> iniTopo(File file) throws IllegalAccessException {
        List<Map> maps = this.parseTxt(file);
        List<WeiXingData> wxData = this.initNet(maps);
        wxData = this.initChangeTopo(wxData);

        return wxData;
    }

    @Override
    public List<WeiXingData> changeTopo(List<WeiXingData> wxData, int time) {
        for(int i=0;i<wxData.size();i++){
            wxData.get(i).setLastime(time);
        }
        wxData = this.addAxis(wxData);
        this.addIndex(wxData);
        this.checkIndex(wxData);

        return wxData;
    }

    @Override
    public List<WeiXingData> initChangeTopo(List<WeiXingData> wxData) {
        wxData = this.addSpeed(wxData);
        wxData = this.addAxis(wxData);
        this.checkWX(wxData);
        this.addIndex(wxData);
        this.checkIndex(wxData);

        return wxData;
    }
}

